package com.stable.actor.network;

import com.stable.actor.core.ActorRef;
import com.stable.actor.core.ActorSystem;
import com.stable.actor.core.RemoteActorRef;
import lombok.extern.slf4j.Slf4j;

/**
 * 消息分发器 - 负责将接收到的消息路由到正确的Actor
 */
@Slf4j
public class MessageDispatcher {
    private final ActorSystem actorSystem;

    public MessageDispatcher(ActorSystem actorSystem) {
        this.actorSystem = actorSystem;
    }

    /**
     * 分发消息到目标Actor
     */
    public Object dispatchMessage(ProtocolMessage message) {
        try {
            String targetPath = message.getTargetPath();
            Object payload = message.getPayload();

            log.debug("🔄 分发消息到: {}, 消息ID: {}", targetPath, message.getMessageId());

            // 创建发送者引用
            ActorRef sender = createSenderRef(message);

            // 直接路由消息到目标Actor
            actorSystem.sendMessage(targetPath, payload, sender);

            // 对于需要同步响应的场景，可以返回响应对象
            // 这里返回null表示异步处理
            return null;

        } catch (Exception e) {
            log.error("❌ 分发消息失败: {}", message.getMessageId(), e);
            throw new RuntimeException("Failed to dispatch message", e);
        }
    }

    /**
     * 创建发送者引用
     */
    private ActorRef createSenderRef(ProtocolMessage message) {
        // 如果发送者是远程Actor，创建远程引用
        if (message.getSenderPath() != null && !message.getSenderPath().equals("no-sender")) {
            return parseSenderPath(message.getSenderPath());
        }
        return null;
    }

    /**
     * 解析发送者路径为ActorRef
     */
    private ActorRef parseSenderPath(String senderPath) {
        try {
            // 检查是否是远程路径格式 (host:port/path)
            if (senderPath.contains(":")) {
                // 远程发送者
                String[] parts = senderPath.split("/", 2);
                String[] hostPort = parts[0].split(":");
                if (hostPort.length == 2) {
                    String host = hostPort[0];
                    int port = Integer.parseInt(hostPort[1]);
                    String path = "/" + (parts.length > 1 ? parts[1] : "");
                    return new RemoteActorRef(host, port, path, actorSystem);
                }
            }

            // 本地发送者或无法解析的路径
            // 尝试查找本地Actor
            ActorRef localSender = actorSystem.findActor(senderPath);
            if (localSender != null) {
                return localSender;
            }

            // 创建基础的ActorRef表示
            return new ActorRef(senderPath, null, actorSystem, false);

        } catch (Exception e) {
            log.warn("解析发送者路径失败: {}, 使用null发送者", senderPath, e);
            return null;
        }
    }

    /**
     * 处理远程ask响应
     */
    public void dispatchAskResponse(ProtocolMessage message) {
        try {
            Object payload = message.getPayload();
            if (payload instanceof ActorRef.RemoteAskResponse) {
                ActorRef.RemoteAskResponse askResponse = (ActorRef.RemoteAskResponse) payload;
                ActorRef.handleAskResponse(askResponse.getCorrelationId(), askResponse.getResponse());
                log.debug("处理远程ask响应: {}", askResponse.getCorrelationId());
            }
        } catch (Exception e) {
            log.error("处理远程ask响应失败: {}", message.getMessageId(), e);
        }
    }

    /**
     * 检查消息类型并分发给合适的处理器
     */
    public void dispatch(ProtocolMessage message) {
        try {
            Object payload = message.getPayload();

            // 检查是否是ask响应
            if (payload instanceof ActorRef.RemoteAskResponse) {
                dispatchAskResponse(message);
                return;
            }

            // 检查是否是远程ask消息
            if (payload instanceof ActorRef.RemoteAskWrapper) {
                dispatchRemoteAskMessage(message);
                return;
            }

            // 普通消息分发
            dispatchMessage(message);

        } catch (Exception e) {
            log.error("分发消息失败: {}", message.getMessageId(), e);
        }
    }

    /**
     * 处理远程ask消息
     */
    private void dispatchRemoteAskMessage(ProtocolMessage message) {
        try {
            ActorRef.RemoteAskWrapper askWrapper = (ActorRef.RemoteAskWrapper) message.getPayload();
            String targetPath = message.getTargetPath();

            log.debug("处理远程ask消息: {} -> {}, correlationId: {}",
                    message.getSenderPath(), targetPath, askWrapper.getCorrelationId());

            // 创建发送者引用（包含回复信息）
            ActorRef sender = createAskSenderRef(message, askWrapper);

            // 分发原始消息
            actorSystem.sendMessage(targetPath, askWrapper.getOriginalMessage(), sender);

        } catch (Exception e) {
            log.error("处理远程ask消息失败: {}", message.getMessageId(), e);
        }
    }

    /**
     * 创建ask消息的发送者引用
     */
    private ActorRef createAskSenderRef(ProtocolMessage message, ActorRef.RemoteAskWrapper askWrapper) {
        // 创建能够回复ask的远程发送者
        return new ActorRef(message.getSenderPath(), null, actorSystem, false) {
            @Override
            public void tell(Object response, ActorRef sender) {
                // 当目标Actor回复时，发送ask响应回原始发送者
                ActorRef.RemoteAskResponse askResponse =
                        new ActorRef.RemoteAskResponse(askWrapper.getCorrelationId(), response);

                // 发送响应回原始系统
                String originalHost = extractHostFromPath(message.getSenderPath());
                int originalPort = askWrapper.getReplyPort();

                if (originalHost != null && originalPort > 0) {
                    actorSystem.sendRemoteMessage(originalHost, originalPort,
                            message.getSenderPath(), askResponse, null);
                } else {
                    log.warn("无法发送ask响应，缺少原始系统信息: {}", message.getSenderPath());
                }
            }
        };
    }

    /**
     * 从路径中提取主机名
     */
    private String extractHostFromPath(String path) {
        if (path.contains(":")) {
            String[] parts = path.split("/", 2);
            String[] hostPort = parts[0].split(":");
            if (hostPort.length >= 1) {
                return hostPort[0];
            }
        }
        return null;
    }
}
